Skip to content

Conversation

@BinBashBanana
Copy link
Contributor

Changes:

  • Added new AudioWorklet driver, a fast callback-based audio driver (requires threads)
    • Handles suspended audio contexts (i.e. if RetroArch starts before a user gesture on the page), should also handle interrupted contexts
    • Has several options for blocking:
      • PROXY_TO_PTHREAD and ASYNC will sleep in the write function
      • ALLOW_AUDIO_BUSYWAIT will busy spin, like rwebaudio does (not recommended)
      • EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK has extra buffer space so that writes that would block can be waited for outside of the write function, and includes the following 2 modes:
        • EMSCRIPTEN_AUDIO_ASYNC_BLOCK sleeps directly in the main loop, this uses a new MIN_ASYNC option that only instruments a few functions instead of almost the entire program (thanks @m4xw!)
        • EMSCRIPTEN_AUDIO_FAKE_BLOCK changes the main loop timing to simulate a block while still being CPU usage-friendly. No, this doesn't cause issues :)
    • I've tested it on multiple devices and with different screen refresh rates and with PAL roms, slow-motion, etc.
  • Further cleaned up Makefile.emscripten, added descriptions to some options
  • Use HAVE_EXTRA_WASMFS=1 to enable OPFS/FetchFS now; HAVE_WASMFS=1 will only enable WasmFS and not the extra FS backends.
  • Added platform_emscripten.h since we have several functions used from there now
  • Fixed battery level always showing 100% or 0% (I wrote int instead of float, oops)
  • Don't export internal update_* functions for platform_emscripten
  • Fixed framerate issues in PROXY_TO_PTHREAD by running requestAnimationFrame (vsync) off the main browser thread, then use a signal to wait
  • Fixed use-after-free in rwebinput (yikes, but affected PROXY_TO_PTHREAD only)
  • Further decreased proxied calls in rwebpad_joypad, also reduced static globals
  • Made threads always use emscripten_thread_sleep (nanosleep used this internally)
  • Restored script downloading to threaded web player, thanks @JoeOsborn for Use mainScriptUrlOrBlob if present under EXPORT_ES6 emscripten-core/emscripten#23890 (in emscripten 4.0.6)
  • Fixed possible error in data migration in threaded web player

BTW - regarding #15479 (comment):

The gamepad I have connected seems to be detected but it doesn't do anything. Upon disconnecting and connecting again, the autoconfig dialog pops up showing that it has detected the controller and configured it, but then control goes haywire and it sporadically goes up and down all over the place on its own.

This seems to be a firefox windows issue. Even luser.github.io/gamepadtest shows the same behavior.

Let me know what you think! Also, this still needs to be tested on safari.

@BinBashBanana
Copy link
Contributor Author

Just bumped the default audio latency for AudioWorklet back down to 64 ms, though rwebaudio and OpenAL still need the higher latency in emscripten.
Also fixed a bug in the web player where the delete data buttons would get stuck, and updated the changelog.

BTW - for building RetroArch with AudioWorklet, use these extra variables: HAVE_THREADS=1 HAVE_AL=0 HAVE_AUDIOWORKLET=1. Optionally add MIN_ASYNC=1, but there is no difference to the user.

$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
@if [ "$(HAVE_AUDIOWORKLET)" = 1 ]; then\
tr -d '\n' < "$${TARGET%%\.js}.aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js;\
sed -i "s/\"$${TARGET%%\.js}\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" "$@";\
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sed and make both have some differences on Mac OS here, so I was able to get it compiling on Mac and Linux with this variation of the $(TARGET) rule (there is a little duplication unfortunately).

I also tweaked the $(libretro_new) rule to only do the mv if the file with the wrong suffix exists. mv -f ... || true would be another valid choice there.

diff --git a/Makefile.emscripten b/Makefile.emscripten
index 83db5df9b0..36aeb6306c 100644
--- a/Makefile.emscripten
+++ b/Makefile.emscripten
@@ -293,18 +293,23 @@ RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
 
 all: $(TARGET)
 
-$(libretro_new) : $(libretro)
+$(libretro_new) : $(wildcard libretro)
 	mv -f $(libretro) $(libretro_new)
 
 # until emscripten adds something like WASM_WORKERS=2 but for audio worklets, DIY.
+ifeq ($(HAVE_AUDIOWORKLET), 1)
+TARGET_BASE := $(LIBRETRO)_libretro
+$(TARGET): $(RARCH_OBJ) $(libretro_new)
+	@$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
+	$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
+	$(Q)tr -d '\n' < "$(TARGET_BASE).aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js
+	$(Q)sed -i.bak -e "s/\"$(TARGET_BASE)\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" -- "$@"
+	$(Q)rm -f "$(TARGET_BASE).aw.js" _audioworklet.js "$@".bak
+else
 $(TARGET): $(RARCH_OBJ) $(libretro_new)
 	@$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
 	$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
-	@if [ "$(HAVE_AUDIOWORKLET)" = 1 ]; then\
-		tr -d '\n' < "$${TARGET%%\.js}.aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js;\
-		sed -i "s/\"$${TARGET%%\.js}\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" "$@";\
-		rm "$${TARGET%%\.js}.aw.js" _audioworklet.js;\
-	fi
+endif
 
 $(OBJDIR)/%.o: %.c
 	@mkdir -p $(dir $@)

#elif defined(__wiiu__)
#include "../audio/drivers/wiiu_audio.c"
#elif defined(EMSCRIPTEN)
#elif defined(HAVE_RWEBAUDIO)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to add the audioworklet driver in here somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why rwebaudio is in griffin in the first place, maybe emscripten used to build using griffin? It probably doesn't matter, but I fixed this condition just in case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I like these improvements to my sketch for cross platform sed. I’ll review the code changes once I do some testing tomorrow.

Copy link
Contributor

@JoeOsborn JoeOsborn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I'm very happy to see this. Seems to work great in Safari on Mac and on iOS.

@BinBashBanana
Copy link
Contributor Author

There are still a couple more (minor and iOS safari specific) issues that I would like to resolve before this is merged.

@BinBashBanana
Copy link
Contributor Author

That should be it! We're thinking the other bug - occasionally freezing - was due to using an out of date emscripten version (I was unable to reproduce it.)

Copy link
Contributor

@ethanaobrien ethanaobrien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice job

emscripten_thread_sleep(msec);
}
#elif defined(EMSCRIPTEN)
#define retro_sleep(msec) (emscripten_thread_sleep(msec))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you also check to make sure this was at least compiled with threads? Or are we assuming asyncify or threads is always true?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above condition, which will be preferred if it isn't compiled with threads.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh - emscripten_thread_sleep also works on the main thread, but it busy spins so it just locks the page. It isn't used in that case anyway.

@LibretroAdmin
Copy link
Contributor

Is it alright if I merge this? Or does work still need to be done?

@BinBashBanana
Copy link
Contributor Author

Yep, this is ready!

@LibretroAdmin LibretroAdmin merged commit 82d8b96 into libretro:master Apr 10, 2025
31 checks passed
pstef pushed a commit to pstef/RetroArch that referenced this pull request Apr 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants